package com.newfiber.system.third;

import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.annotation.JSONField;
import com.newfiber.common.security.utils.DictUtils;
import com.newfiber.system.api.domain.SysDept;
import com.newfiber.system.api.domain.SysDictData;
import com.newfiber.system.api.domain.SysUser;
import com.newfiber.system.service.ISysDeptService;
import com.newfiber.system.service.ISysUserService;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

/**
 * @author : X.K
 * @since : 2023/7/31 上午9:15
 */
@Service
public class NanpingSyncService {

	private String apiUrl = "";
	private String tokenHeader = "";
	private String clientId = "";
	private String clientSecret = "";

	private final String TOKEN_URL = "/connect/token";
	private final String USER_URL = "/xmgis/api/identity/external/users";
	private final String DEPT_URL = "/xmgis/api/identity/external/organizations";

	private List<SysUser> existsSysUserList = new ArrayList<>();
	private List<SysDept> existsSysDeptList = new ArrayList<>();

	@Resource
	private ISysUserService sysUserService;

	@Resource
	private ISysDeptService sysDeptService;

	@PostConstruct
	public void init(){
		List<SysDictData> sysDictDataList = DictUtils.getDictCache("nanpin_config");

		Optional<SysDictData> apiUrlDictOptional = sysDictDataList.stream().filter(t -> "apiUrl".equals(t.getDictLabel())).findFirst();
		apiUrlDictOptional.ifPresent(sysDictData -> apiUrl = sysDictData.getDictValue());

		Optional<SysDictData> clientIdDictOptional = sysDictDataList.stream().filter(t -> "clientId".equals(t.getDictLabel())).findFirst();
		clientIdDictOptional.ifPresent(sysDictData -> clientId = sysDictData.getDictValue());

		Optional<SysDictData> clientSecretDictOptional = sysDictDataList.stream().filter(t -> "clientSecret".equals(t.getDictLabel())).findFirst();
		clientSecretDictOptional.ifPresent(sysDictData -> clientSecret = sysDictData.getDictValue());

		existsSysUserList = sysUserService.selectUserList(new SysUser());
		existsSysDeptList = sysDeptService.selectDeptList(new SysDept());

		tokenSync();
		userSync();
		deptSync();
	}

	public void tokenSync(){
		if(StringUtils.isBlank(apiUrl)){
			return;
		}

		Map<String, Object> header = new HashMap<>();
		header.put("client_id", clientId);
		header.put("client_secret", clientSecret);
		header.put("scope", "IdentityService");
		header.put("grant_type", "client_credentials");
		String httpTokenResult = HttpUtil.createPost(apiUrl.concat(TOKEN_URL)).form(header).execute().body();
		Result<Token> tokenResult = JSONObject.parseObject(httpTokenResult, new TypeReference<Result<Token>>(){});
		tokenHeader = "Bearer " + tokenResult.getData().getAccessToken();
	}

	/**
	 *
	 */
	public void userSync(){
		if(StringUtils.isBlank(apiUrl)){
			return;
		}

		String bizDataResult = HttpUtil.createGet(apiUrl.concat(USER_URL)).
			header("Authorization", tokenHeader).
			header("Content-Type", "application/json").execute().body();
		PageResult<NanpinUser> nanpinUserResult = JSONObject.parseObject(bizDataResult, new TypeReference<PageResult<NanpinUser>>(){});
		List<NanpinUser> nanpinUserList = nanpinUserResult.items;
		for(NanpinUser nanpinUser : nanpinUserList){
			String md5 = DigestUtil.md5Hex(JSONObject.toJSONString(nanpinUser));
			Optional<SysUser> sysUserMd5Optional = existsSysUserList.stream().filter(t -> t.getMd5().equals(md5)).findAny();
			// 如果MD5已变更，则新增或修改
			if(!sysUserMd5Optional.isPresent()){
				Optional<SysUser> sysUserThirdIdOptional = existsSysUserList.stream().filter(t -> t.getThirdId().equals(nanpinUser.getThirdId())).findAny();
				if(sysUserThirdIdOptional.isPresent()){
					// 更新
					SysUser sysUser = sysUserThirdIdOptional.get();
					BeanUtils.copyProperties(nanpinUser, sysUser);
					sysUser.setMd5(md5);
					sysUserService.updateUser(sysUser);

					existsSysUserList.add(sysUser);
				}else{
					// 新增
					SysUser sysUser = NanpinUser.wrapper(nanpinUser);
					sysUser.setMd5(md5);
					sysUserService.registerUser(sysUser);

					existsSysUserList.add(sysUser);
				}
			}
		}
	}

	public void deptSync(){
		if(StringUtils.isBlank(apiUrl)){
			return;
		}

		String bizDataResult = HttpUtil.createGet(apiUrl.concat(DEPT_URL)).
			header("Authorization", tokenHeader).
			header("Content-Type", "application/json").execute().body();
		PageResult<NanpinDept> nanpinDeptResult = JSONObject.parseObject(bizDataResult, new TypeReference<PageResult<NanpinDept>>(){});
		List<NanpinDept> nanpinDeptList = nanpinDeptResult.items;
		for(NanpinDept nanpinDept : nanpinDeptList){
			String md5 = DigestUtil.md5Hex(JSONObject.toJSONString(nanpinDept));
			Optional<SysDept> sysDeptMd5Optional = existsSysDeptList.stream().filter(t -> t.getMd5().equals(md5)).findAny();
			// 如果MD5已变更，则新增或修改
			if(!sysDeptMd5Optional.isPresent()){
				Optional<SysDept> sysDeptThirdIdOptional = existsSysDeptList.stream().filter(t -> t.getThirdId().equals(nanpinDept.getThirdId())).findAny();
				if(sysDeptThirdIdOptional.isPresent()){
					// 更新
					SysDept sysDept = sysDeptThirdIdOptional.get();
					BeanUtils.copyProperties(nanpinDept, sysDept);
					sysDept.setMd5(md5);
					sysDeptService.updateDept(sysDept);

					existsSysDeptList.add(sysDept);
				}else{
					// 新增
					SysDept sysDept = NanpinDept.wrapper(nanpinDept);
					sysDept.setMd5(md5);
					sysDeptService.insertDept(sysDept);

					existsSysDeptList.add(sysDept);
				}
			}
		}

		// TODO 更新parentId

	}

	@Data
	public static class Result<T>{
		int code;
		String message;
		T data;
	}

	@Data
	public static class PageResult<T>{
		private int totalCount;
		private List<T> items;
	}

	@Data
	public static class Token{
		@JSONField(name = "access_token")
		String accessToken;
	}

	@Data
	public static class NanpinUser{
		@JSONField(name = "id")
		private String thirdId;

		private String userName;

		@JSONField(name = "surname")
		private String nickName;

		@JSONField(name = "phoneNumber")
		private String phonenumber;

		private Date creationTime;
		private Date lastModificationTime;
		private String organizationUnits;

		public static SysUser wrapper(NanpinUser nanpinUser){
			SysUser sysUser = new SysUser();
			BeanUtils.copyProperties(nanpinUser, sysUser);
			return sysUser;
		}
	}

	@Data
	public static class NanpinDept{

		/** 部门ID */
		@JSONField(name = "id")
		private String thirdId;

		/** 父部门ID */
		@JSONField(name = "parentId")
		private String parentThirdId;

		/** 部门名称 */
		@JSONField(name = "displayName")
		private String deptName;

		private Date creationTime;
		private Date lastModificationTime;

		public static SysDept wrapper(NanpinDept nanpinDept){
			SysDept sysDept = new SysDept();
			BeanUtils.copyProperties(nanpinDept, sysDept);
			return sysDept;
		}
	}
}
